home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / malloc / malloc.c
Text File  |  1988-11-30  |  36KB  |  1,113 lines

  1.  
  2. From mnetor!seismo!ll-xn!mit-amt!mit-eddie!mirror!sources-request Fri Jul 18 22:24:02 EDT 1986
  3. Article 444 of mod.sources:
  4. Relay-Version: version B 2.10.2 9/18/84; site lsuc.UUCP
  5. Path: lsuc!mnetor!seismo!ll-xn!mit-amt!mit-eddie!mirror!sources-request
  6. >From: sources-request@mirror.UUCP
  7. Newsgroups: mod.sources
  8. Subject: v06i054:  A "smarter" malloc (malloc)
  9. Message-ID: <141@mirror.UUCP>
  10. Date: 15 Jul 86 11:31:22 GMT
  11. Date-Received: 16 Jul 86 07:29:40 GMT
  12. Sender: rs@mirror.UUCP
  13. Lines: 1028
  14. Approved: rs@mirror.UUCP
  15.  
  16. Submitted by: cca!astrovax!wls (William L. Sebok)
  17. Mod.sources: Volume 6, Issue 54
  18. Archive-name: malloc
  19.  
  20. --------Cut Here----------
  21. # This is a shell archive.  Remove anything before this line,
  22. # then unpack it by saving it in a file and typing "sh file".
  23. #
  24. # Wrapped by astrovax!wls on Thu Jul  3 13:20:20 EDT 1986
  25. # Contents:  README malloc.3 forget.3 malloc.h malloc.c free.c realloc.c
  26. #       forget.c tstmalloc.c asm.sed malloc.adb
  27.  
  28. echo x - README
  29. sed 's/^@//' > "README" <<'@//E*O*F README//'
  30. This is the malloc()/free()/realloc()/forget() package used at astrovax.
  31.  
  32. It does not have the property of the 4.2 BSD malloc of allocating huge amounts
  33. of excess memory.  Image processing is done here and large malloc requests
  34. are not rare.  It is quite undesirable when one asks for 4.1 megabytes of memory
  35. to have it try to return 8 megabytes and to fail because the process goes over
  36. quota or there is not enough swap space.
  37.  
  38. Also this malloc does not have the property of the 4.1 BSD malloc that a search
  39. for free memory traverses a linked list that covers all previous allocations,
  40. causing thrashing by touching them and thus paging them back into memory.
  41.  
  42. Hopefully this malloc covers the best of both worlds.  There is a fair attempt
  43. at storage compaction, merging freed areas with adjacent free areas and
  44. optionally returning freed areas adjacent to the break back to the system,
  45. thereby shrinking the size of the process.
  46.  
  47. It is also allowable and compatible with this package to obtain memory by the
  48. use of the sbrk() system call.  This memory can be reclaimed and returned to
  49. the malloc arena by the use of the provided forget() function.  This function
  50. is intended to provide the functionality of the Forth FORGET primitive in
  51. an environment that also includes malloc and free.
  52.  
  53. The main disadvantage of this package is a larger storage overhead of 24 bytes
  54. per memory area, due to the fact that each area is linked into two
  55. bi-directional chains.
  56.  
  57. Non-vax users should edit the commented system-dependent parts of Makefile and
  58. malloc.h for the requirements of one's own computer.
  59.  
  60. Bill Sebok                      Princeton University, Astrophysics
  61. {allegra,akgua,cbosgd,decvax,ihnp4,noao,philabs,princeton,vax135}!astrovax!wls
  62. @//E*O*F README//
  63. chmod u=rw,g=r,o=r README
  64.  
  65. echo x - malloc.3
  66. sed 's/^@//' > "malloc.3" <<'@//E*O*F malloc.3//'
  67. @.TH MALLOC 3  "30 June 1986"
  68. @.SH NAME
  69. malloc, free, realloc \- memory allocator
  70. @.SH SYNOPSIS
  71. @.nf
  72. @.B char *malloc(size)
  73. @.B Size size;
  74. @.PP
  75. @.B void free(ptr)
  76. @.B char *ptr;
  77. @.PP
  78. @.B char *realloc(ptr, size)
  79. @.B char *ptr;
  80. @.B Size size;
  81. @.PP
  82. @.B extern char endfree
  83. @.PP
  84. @.B extern void (*mlabort)()
  85. @.fi
  86. @.PP
  87. Where
  88. @.I Size
  89. is an integer large enough to hold a char pointer.
  90. @.SH DESCRIPTION
  91. @.I Malloc
  92. and
  93. @.I free
  94. provide a simple general-purpose memory allocation package.
  95. @.I Malloc
  96. returns a pointer to a block of at least
  97. @.I size
  98. bytes beginning on the boundary of the most stringent alignment required
  99. by the architecture.
  100. @.PP
  101. The argument to
  102. @.I free
  103. is a pointer to a block previously allocated by
  104. @.IR malloc ;
  105. this space is made available for further allocation,
  106. but its contents are left undisturbed.
  107. @.PP
  108. Needless to say, grave disorder will result if the space assigned by
  109. @.I malloc
  110. is overrun or if some random number is handed to
  111. @.IR free .
  112. @.PP
  113. @.I Malloc
  114. maintains multiple lists of free blocks according to size,
  115. allocating space from the appropriate list.
  116. It calls
  117. @.I brk
  118. (see
  119. @.IR brk (2))
  120. to get more memory from the system when there is no
  121. suitable space already free.
  122. @.PP
  123. @.I Free
  124. makes an attempt to merge newly freed memory with adjacent free areas.
  125. If the result of this merging is an area that touches the system break
  126. (the current location of the highest valid address of the data segment of the
  127. process) and if
  128. @.I
  129. endfree
  130. has a non-zero value,  then break is moved back, contracting the process
  131. size and releasing the memory back to the system.
  132. @.PP
  133. By default
  134. @.I endfree
  135. has a value of 0, which disables the release of memory back to the system.
  136. @.PP
  137. It is valid to also allocate memory by the use of
  138. @.I sbrk(3)
  139. or by moving up the break with
  140. @.I brk(3).
  141. This memory may be reclaimed and returned to
  142. the \fImalloc\fP/\fIfree\fP arena by the use of
  143. @.I forget
  144. (see \fIforget\fP(3)).
  145. @.PP
  146. @.I Realloc
  147. changes the size of the block pointed to by
  148. @.I ptr
  149. to
  150. @.I size
  151. bytes and returns a pointer to the (possibly moved) block.
  152. The contents will be unchanged up to the lesser of the new and old sizes.
  153. @.PP
  154. In order to be compatible with older versions,
  155. if
  156. @.I endfree
  157. is 0, then
  158. @.I realloc
  159. also works if
  160. @.I ptr
  161. points to a block freed since the last call of
  162. @.I malloc
  163. or
  164. @.I realloc.
  165. Sequences of
  166. @.I free, malloc
  167. and
  168. @.I realloc
  169. were previously used to attempt storage compaction.
  170. This procedure is no longer recommended.
  171. In this implementation
  172. @.I Realloc,
  173. @.I malloc
  174. and
  175. @.I free
  176. do a fair amount of their own storage compaction anyway.
  177. @.SH DIAGNOSTICS
  178. @.I Malloc, realloc
  179. return a null pointer (0) if there is no available memory or if the arena
  180. has been detectably corrupted by storing outside the bounds of a block.
  181. @.I Realloc
  182. makes an attempt to detect and return a null pointer when the break has been
  183. moved so that the requested address is no longer valid.
  184. @.I Malloc
  185. may be recompiled to check the arena very stringently on every transaction;
  186. those sites with a source code license may do this by recompiling the source
  187. with  -Ddebug .
  188. @.PP
  189. On detection of corruption of the malloc arena the normal response is an
  190. abort with a core dump.  This response can be changed by placing a pointer to
  191. a function with the desired response into the extern pointer
  192. @.I mlabort.
  193. @.SH ALGORITHM
  194. @.I Malloc
  195. returns a block of size equal to the size requested plus an overhead (24
  196. bytes for a 32 bit machine).
  197. Freed memory is linked into a chain selected by the size of the freed area
  198. (currently, memory size of items in a chain is between two adjacent powers of
  199. 2).
  200. The search for memory starts with the chain whose length index is at least
  201. equal to the size of the request and proceeds if unsuccessful to larger
  202. memory size chains.  If there is any surplus memory left after the filling
  203. of a request it is returned to the appropriate free list chain.
  204. @.SH BUGS
  205. When
  206. @.I realloc
  207. returns 0, the block pointed to by
  208. @.I ptr
  209. may have been destroyed.
  210. @//E*O*F malloc.3//
  211. chmod u=rw,g=r,o=r malloc.3
  212.  
  213. echo x - forget.3
  214. sed 's/^@//' > "forget.3" <<'@//E*O*F forget.3//'
  215. @.TH FORGET 3  "30 June 1986"
  216. @.SH NAME
  217. forget \- reclaim sbrk'ed memory into malloc arena
  218. @.SH SYNOPSIS
  219. @.nf
  220. @.B void forget(ptr)
  221. @.B char *ptr;
  222. @.PP
  223. @.B extern char endfree
  224. @.SH DESCRIPTION
  225. @.I Forget
  226. provides a way of reclaiming memory obtained by
  227. @.I sbrk(3)
  228. and returning it to the malloc arena.  All such memory above
  229. @.I ptr
  230. (the "forget point") is marked free and merged if possible with adjacent
  231. free areas.  If
  232. @.I endfree
  233. is non-zero any such memory adjacent to the "break" (the highest valid
  234. data address for the process) is released to the system by moving back
  235. the break.
  236. @.PP
  237. This function was written to provide the functionality of the Forth
  238. FORGET primitive in an environment where
  239. a dictionary is grown by
  240. @.I sbrk
  241. and
  242. @.I malloc
  243. and
  244. @.I free
  245. are also present.
  246. @.SH BUGS
  247. When the specified forget point is below the initial end of the program,
  248. disaster can result.
  249. @//E*O*F forget.3//
  250. chmod u=rw,g=r,o=r forget.3
  251.  
  252. echo x - malloc.h
  253. sed 's/^@//' > "malloc.h" <<'@//E*O*F malloc.h//'
  254. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  255.  * A  "smarter" malloc                          William L. Sebok
  256.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  257.  *      Algorithm:
  258.  *       Assign to each area an index "n". This is currently proportional to
  259.  *      the log 2 of size of the area rounded down to the nearest integer.
  260.  *      Then all free areas of storage whose length have the same index n are
  261.  *      organized into a chain with other free areas of index n (the "bucket"
  262.  *      chain). A request for allocation of storage first searches the list of
  263.  *      free memory.  The search starts at the bucket chain of index equal to
  264.  *      that of the storage request, continuing to higher index bucket chains
  265.  *      if the first attempt fails.
  266.  *      If the search fails then new memory is allocated.  Only the amount of
  267.  *      new memory needed is allocated.  Any old free memory left after an
  268.  *      allocation is returned to the free list.
  269.  *
  270.  *        All memory areas (free or busy) handled by malloc are also chained
  271.  *      sequentially by increasing address (the adjacency chain).  When memory
  272.  *      is freed it is merged with adjacent free areas, if any.  If a free area
  273.  *      of memory ends at the end of memory (i.e. at the break), and if the
  274.  *      variable "endfree" is non-zero, then the break is contracted, freeing
  275.  *      the memory back to the system.
  276.  *
  277.  *      Notes:
  278.  *              ov_length field includes sizeof(struct overhead)
  279.  *              adjacency chain includes all memory, allocated plus free.
  280.  */
  281.  
  282. /* the following items may need to be configured for a particular machine */
  283.  
  284. /* alignment requirement for machine (in bytes) */
  285. #define NALIGN  4
  286.  
  287. /* size of an integer large enough to hold a character pointer */
  288. typedef long    Size;
  289.  
  290. /*
  291.  * CURBRK returns the value of the current system break, i.e., the system's
  292.  * idea of the highest legal address in the data area.  It is defined as
  293.  * a macro for the benefit of systems that have provided an easier way to
  294.  * obtain this number (such as in an external variable)
  295.  */
  296.  
  297. #ifndef CURBRK
  298. #define CURBRK  sbrk(0)
  299. extern char *sbrk();
  300. #else  CURBRK
  301. #       if      CURBRK == curbrk
  302. extern Size curbrk;
  303. #       endif
  304. #endif CURBRK
  305.  
  306. /*
  307.  * note that it is assumed that CURBRK remembers the last requested break to
  308.  * the nearest byte (or at least the nearest word) rather than the nearest page
  309.  * boundary.  If this is not true then the following BRK macro should be
  310.  * replaced with one that remembers the break to within word-size accuracy.
  311.  */
  312.  
  313. #ifndef BRK
  314. #define BRK(x)  brk(x)
  315. extern char *brk();
  316. #endif  BRK
  317.  
  318. /* END of machine dependent portion */
  319.  
  320. #define MAGIC_FREE      0x548a934c
  321. #define MAGIC_BUSY      0xc139569a
  322.  
  323. #define NBUCKETS        18
  324.  
  325. struct qelem {
  326.         struct qelem *q_forw;
  327.         struct qelem *q_back;
  328. };
  329.  
  330. struct overhead {
  331.         struct qelem    ov_adj;         /* adjacency chain pointers */ 
  332.         struct qelem    ov_buk;         /* bucket chain pointers */
  333.         long            ov_magic;
  334.         Size            ov_length;
  335. };
  336.  
  337. /*
  338.  * The following macros depend on the order of the elements in struct overhead
  339.  */
  340. #define TOADJ(p)        ((struct qelem *)(p))
  341. #define FROMADJ(p)      ((struct overhead *)(p))
  342. #define FROMBUK(p)      ((struct overhead *)( (char *)p - sizeof(struct qelem)))
  343. #define TOBUK(p)        ((struct qelem *)( (char *)p + sizeof(struct qelem)))
  344.  
  345. #ifdef MALLOC
  346. /*
  347.  * return to the system memory freed adjacent to the break 
  348.  * default is Off
  349.  */
  350. char endfree = 0;
  351.  
  352. /* sizes of buckets currently proportional to log 2() */
  353. Size mlsizes[] = {0, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
  354.         65536, 131072, 262144, 524288, 1048576, 2097152, 4194304};
  355.  
  356. /* head of adjacency chain */
  357. struct qelem adjhead = { &adjhead, &adjhead };
  358.  
  359. /* head of bucket chains */
  360. struct qelem buckets[NBUCKETS] = {
  361.         &buckets[0],  &buckets[0],      &buckets[1],  &buckets[1],
  362.         &buckets[2],  &buckets[2],      &buckets[3],  &buckets[3],
  363.         &buckets[4],  &buckets[4],      &buckets[5],  &buckets[5],
  364.         &buckets[6],  &buckets[6],      &buckets[7],  &buckets[7],
  365.         &buckets[8],  &buckets[8],      &buckets[9],  &buckets[9],
  366.         &buckets[10], &buckets[10],     &buckets[11], &buckets[11],
  367.         &buckets[12], &buckets[12],     &buckets[13], &buckets[13],
  368.         &buckets[14], &buckets[14],     &buckets[15], &buckets[15],
  369.         &buckets[16], &buckets[16],     &buckets[17], &buckets[17]
  370. };
  371.  
  372. void (*mlabort)() = {0};
  373.  
  374. #else
  375. extern char endfree;
  376. extern struct qelem adjhead, buckets[NBUCKETS];
  377. extern Size mlsizes[NBUCKETS];
  378. extern void (*mlabort)();
  379. #endif
  380.  
  381. extern void insque(), remque();
  382. extern void free(), mllcerr();
  383. extern char *malloc(), *realloc();
  384.  
  385. #ifdef debug
  386. # define ASSERT(p,q)    if (!(p)) mllcerr(q)
  387. #else
  388. # define ASSERT(p,q)
  389. #endif
  390. @//E*O*F malloc.h//
  391. chmod u=rw,g=r,o=r malloc.h
  392.  
  393. echo x - malloc.c
  394. sed 's/^@//' > "malloc.c" <<'@//E*O*F malloc.c//'
  395. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  396.  * A  "smarter" malloc v1.0                     William L. Sebok
  397.  *                                      Sept. 24, 1984 rev. June 30,1986
  398.  *
  399.  *      malloc allocates and returns a pointer to a piece of memory nbytes
  400.  *      in size.
  401.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  402.  
  403. #define MALLOC
  404. #include "malloc.h"
  405.  
  406. #define NULL    0
  407.  
  408. char *
  409. malloc(nbytes)
  410.         Size nbytes;
  411. {
  412.         register struct overhead *p, *q;
  413.         register struct qelem *bucket;
  414.         register Size surplus;
  415.         Size mlindx();
  416.  
  417.         nbytes = ((nbytes + (NALIGN-1)) & ~(NALIGN-1))
  418.                 + sizeof(struct overhead);
  419.  
  420.         for (
  421.             bucket = &buckets[mlindx(nbytes)];
  422.             bucket < &buckets[NBUCKETS];
  423.             bucket++
  424.         ) { 
  425.                 register struct qelem *b;
  426.                 for(b = bucket->q_forw; b != bucket; b = b->q_forw) {
  427.                         p = FROMBUK(b);
  428.                         ASSERT(p->ov_magic == MAGIC_FREE,
  429. "\nmalloc: Entry not marked FREE found on Free List!\n");
  430.                         if (p->ov_length >= nbytes) {
  431.                                 remque(b);
  432.                                 surplus = p->ov_length - nbytes;
  433.                                 goto foundit;
  434.                         }
  435.                 }
  436.         }
  437.  
  438.         /* obtain additional memory from system */
  439.         {
  440.                 register Size i;
  441.                 p = (struct overhead *)CURBRK;
  442.  
  443.                 i = ((Size)p)&(NALIGN-1);
  444.                 if (i != 0)
  445.                         p = (struct overhead *)((char *)p + NALIGN - i);
  446.  
  447.                 if (BRK((char *)p + nbytes))
  448.                         return(NULL);
  449.  
  450.                 p->ov_length = nbytes;
  451.                 surplus = 0;
  452.  
  453.                 /* add to end of adjacency chain */
  454.                 ASSERT((FROMADJ(adjhead.q_back)) < p,
  455. "\nmalloc: Entry in adjacency chain found with address lower than Chain head!\n"
  456.                         );
  457.                 insque(TOADJ(p),adjhead.q_back);
  458.         }
  459.  
  460. foundit:
  461.         /* mark surplus memory free */
  462.         if (surplus > sizeof(struct overhead)) {
  463.                 /* if big enough, split it up */
  464.                 q = (struct overhead *)((char *)p + nbytes);
  465.  
  466.                 q->ov_length = surplus;
  467.                 p->ov_length = nbytes;
  468.                 q->ov_magic = MAGIC_FREE;
  469.  
  470.                 /* add surplus into adjacency chain */
  471.                 insque(TOADJ(q),TOADJ(p));
  472.  
  473.                 /* add surplus into bucket chain */
  474.                 insque(TOBUK(q),&buckets[mlindx(surplus)]);
  475.         }
  476.  
  477.         p->ov_magic = MAGIC_BUSY;
  478.         return((char*)p + sizeof(struct overhead));
  479. }
  480.  
  481. /*
  482.  * select the proper size bucket
  483.  */
  484. Size
  485. mlindx(n)
  486. register Size n;
  487. {
  488.         register Size *p, *q, *r;
  489.         p = &mlsizes[0];
  490.         r = &mlsizes[NBUCKETS];
  491.         /* binary search */
  492.         while ((q = (p + (r-p)/2)) > p) {
  493.                 if (n < *q)
  494.                         r = q;
  495.                 else
  496.                         p = q;
  497.         }
  498.         return(q - &mlsizes[0]);
  499. }
  500.  
  501. void
  502. mllcerr(p)
  503. char *p;
  504. {
  505.         register char *q;
  506.         q = p;
  507.         while (*q++);   /* find end of string */
  508.         (void)write(2,p,q-p-1);
  509.         if (mlabort)
  510.                 (*mlabort)();
  511. #ifdef debug
  512.         else
  513.                 abort();
  514. #endif debug
  515. }
  516.  
  517. #ifndef vax
  518. /*
  519.  * The vax has wondrous instructions for inserting and removing items into
  520.  * doubly linked queues.  On the vax the assembler output of the C compiler is
  521.  * massaged by an sed script to turn these function calls into invocations of
  522.  * the insque and remque machine instructions.
  523.  */
  524.  
  525. void
  526. insque(item,queu)
  527. register struct qelem *item, *queu;
  528. /* insert "item" after "queu" */
  529. {
  530.         register struct qelem *pueu;
  531.         pueu = queu->q_forw;
  532.         item->q_forw = pueu;
  533.         item->q_back = queu;
  534.         queu->q_forw = item;
  535.         pueu->q_back = item;
  536. }
  537.  
  538. void
  539. remque(item)
  540. register struct qelem *item;
  541. /* remove "item" */
  542. {
  543.         register struct qelem *queu, *pueu;
  544.         pueu = item->q_forw;
  545.         queu = item->q_back;
  546.         queu->q_forw = pueu;
  547.         pueu->q_back = queu;
  548. }
  549. #endif
  550. @//E*O*F malloc.c//
  551. chmod u=rw,g=r,o=r malloc.c
  552.  
  553. echo x - free.c
  554. sed 's/^@//' > "free.c" <<'@//E*O*F free.c//'
  555. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  556.  *  free                                        William L. Sebok
  557.  * A "smarter" malloc v1.0              Sept. 24, 1984 rev. June 30,1986
  558.  *
  559.  *      free takes a previously malloc-allocated area at mem and frees it.
  560.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  561.  
  562.  
  563. #include "malloc.h"
  564.  
  565. #define NULL    0
  566.  
  567. void
  568. free(mem)
  569. register char *mem;
  570. {
  571.         register struct overhead *p, *q;
  572.         void mlfree_end();
  573.  
  574.         if (mem == NULL)
  575.                 return;
  576.  
  577.         p = (struct overhead *)(mem - sizeof(struct overhead));
  578.  
  579.         /* not advised but allowed */
  580.         if (p->ov_magic == MAGIC_FREE)
  581.                 return;
  582.  
  583.         if (p->ov_magic != MAGIC_BUSY)
  584.                 mllcerr("attempt to free memory not allocated with malloc!\n");
  585.  
  586.         /* try to merge with previous free area */
  587.         q = FROMADJ((TOADJ(p))->q_back);
  588.  
  589.         if (q != FROMADJ(&adjhead)) {
  590.                 ASSERT(q < p,
  591. "\nfree: While trying to merge a free area with a lower adjacent free area,\n\
  592.  addresses were found out of order!\n");
  593.                 /* If lower segment can be merged */
  594.                 if (   q->ov_magic == MAGIC_FREE
  595.                    && (char *)q + q->ov_length == (char *)p
  596.                 ) {
  597.                         /* remove lower address area from bucket chain */
  598.                         remque(TOBUK(q));
  599.  
  600.                         /* remove upper address area from adjacency chain */
  601.                         remque(TOADJ(p));
  602.  
  603.                         q->ov_length += p->ov_length;
  604.                         p->ov_magic = NULL;     /* decommission */
  605.                         p = q;
  606.                 }
  607.         }
  608.  
  609.         /* try to merge with next higher free area */
  610.         q = FROMADJ((TOADJ(p))->q_forw);
  611.  
  612.         if (q != FROMADJ(&adjhead)) {
  613.                 /* upper segment can be merged */
  614.                 ASSERT(q > p,
  615. "\nfree: While trying to merge a free area with a higher adjacent free area,\n\
  616.  addresses were found out of order!\n");
  617.                 if (    q->ov_magic == MAGIC_FREE
  618.                    &&   (char *)p + p->ov_length == (char *)q
  619.                 ) {
  620.                         /* remove upper from bucket chain */
  621.                         remque(TOBUK(q));
  622.  
  623.                         /* remove upper from adjacency chain */
  624.                         remque(TOADJ(q));
  625.  
  626.                         p->ov_length += q->ov_length;
  627.                         q->ov_magic = NULL;     /* decommission */
  628.                 }
  629.         }
  630.  
  631.         p->ov_magic = MAGIC_FREE;
  632.  
  633.         /* place in bucket chain */
  634.         insque(TOBUK(p),&buckets[mlindx(p->ov_length)]);
  635.  
  636.         if (endfree)
  637.                 mlfree_end();
  638.  
  639.         return;
  640. }
  641.  
  642. void
  643. mlfree_end()
  644. {
  645.         register struct overhead *p;
  646.  
  647.         p = FROMADJ(adjhead.q_back);
  648.         if (    /* area is free and at end of memory */
  649.                 p->ov_magic == MAGIC_FREE
  650.             &&  (char*)p + p->ov_length == (char *)CURBRK
  651.         ) {
  652.                 p->ov_magic = NULL;     /* decommission (just in case) */
  653.  
  654.                 /* remove from end of adjacency chain */
  655.                 remque(TOADJ(p));
  656.  
  657.                 /* remove from bucket chain */
  658.                 remque(TOBUK(p));
  659.  
  660.                 /* release memory to system */
  661.                 (void)BRK((char *)p);
  662.         }
  663.         return;
  664. }
  665. @//E*O*F free.c//
  666. chmod u=rw,g=r,o=r free.c
  667.  
  668. echo x - realloc.c
  669. sed 's/^@//' > "realloc.c" <<'@//E*O*F realloc.c//'
  670. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  671.  *  realloc                             William L. Sebok
  672.  * A  "smarter" malloc v1.0             Sept. 24, 1984 rev. June 30,1986
  673.  *
  674.  *      realloc takes previously malloc-allocated area at mem, and tries
  675.  *       to change its size to nbytes bytes, moving it and copying its
  676.  *       contents if necessary.
  677.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  678.  
  679. #include "malloc.h"
  680.  
  681. #ifndef NULL
  682. #define NULL    0
  683. #endif
  684.  
  685. char *
  686. realloc(mem,nbytes)
  687. register char *mem; unsigned nbytes;
  688. {
  689.         register char *newmem;
  690.         register struct overhead *p, *q;
  691.         Size surplus, length;
  692.         char oendfree;
  693.  
  694.         if (mem == NULL)
  695.                 return(malloc(nbytes));
  696.  
  697.         /* if beyond current arena it has to be bad */
  698.         if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead))
  699.                 return(NULL);
  700.         
  701.         p = (struct overhead *)(mem - sizeof(struct overhead));
  702.  
  703.         if (p->ov_magic != MAGIC_BUSY && p->ov_magic != MAGIC_FREE)
  704.                 return(NULL);   /* already gone */
  705.  
  706.         length = p->ov_length;
  707.  
  708.         nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
  709.  
  710.         if (p->ov_magic == MAGIC_BUSY) {
  711.                 oendfree = endfree;     endfree = 0;
  712.                 free(mem);      /* free it but don't let it contract break */
  713.                 endfree = oendfree;
  714.         }
  715.  
  716.         if(  p->ov_magic == MAGIC_FREE
  717.          && (surplus = length - nbytes - sizeof(struct overhead)) >= 0
  718.         ) {
  719.                 /* shrink area in place */
  720.                 if (surplus > sizeof(struct overhead)) {
  721.                         q = (struct overhead *)( (char *)p + nbytes
  722.                                 + sizeof(struct overhead));
  723.                         q->ov_length = surplus;
  724.                         q->ov_magic = MAGIC_FREE;
  725.                         insque(TOADJ(q),TOADJ(p));
  726.                         insque(TOBUK(q),&buckets[mlindx(surplus)]);
  727.                         p->ov_length -= surplus;
  728.                 }
  729.                 /* declare it to be busy */
  730.                 remque(TOBUK(p));
  731.                 p->ov_magic = MAGIC_BUSY;
  732.  
  733.                 if (endfree)
  734.                         mlfree_end();
  735.                 return(mem);
  736.         }
  737.  
  738.         /* if at break, grow in place */
  739.         if (p->ov_magic == MAGIC_FREE && ((char *)p + p->ov_length) == CURBRK) {
  740.                 nbytes += sizeof(struct overhead);
  741.                 BRK((char *)p + nbytes);
  742.                 p->ov_length = nbytes;
  743.                 return(mem);
  744.         }
  745.  
  746.         newmem = malloc(nbytes);
  747.  
  748.         if (newmem != mem && newmem != NULL) {
  749.                 register Size n;
  750.                 n = length - sizeof(struct overhead);
  751.                 nbytes = (nbytes < n) ? nbytes: n;
  752.                 (void)bcopy(mem,newmem,nbytes);
  753.                 /* note:
  754.                  * it is assumed that bcopy does the right thing on overlapping
  755.                  * extents (true on the vax)
  756.                  */
  757.         }
  758.  
  759.         if (endfree)
  760.                 mlfree_end();
  761.  
  762.         return(newmem);
  763. }
  764. @//E*O*F realloc.c//
  765. chmod u=rw,g=r,o=r realloc.c
  766.  
  767. echo x - forget.c
  768. sed 's/^@//' > "forget.c" <<'@//E*O*F forget.c//'
  769. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  770.  *  forget                              William L. Sebok
  771.  * A "smarter" malloc v1.0              Sept. 24, 1984 rev. June 30,1986
  772.  *
  773.  *      forget returns to the malloc arena all memory allocated by sbrk()
  774.  *       above "bpnt".
  775.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  776.  
  777. #include "malloc.h"
  778.  
  779. #define NULL    0
  780.  
  781. void
  782. forget(bpnt)
  783. char *bpnt;
  784. {
  785.         register struct overhead *p, *q, *r, *b;
  786.         register Size l;
  787.         struct overhead *crbrk;
  788.         char pinvalid, oendfree;
  789.  
  790.         /*
  791.          * b = forget point
  792.          * p = beginning of entry
  793.          * q = end of entry, beginning of gap
  794.          * r = end of gap, beginning of next entry (or the break)
  795.          * pinvalid = true when groveling at forget point
  796.          */
  797.  
  798.         pinvalid = 0;
  799.         oendfree = endfree;     endfree = 0;
  800.         b = (struct overhead *)bpnt;
  801.         p = FROMADJ(adjhead.q_back);
  802.         r = crbrk = (struct overhead *)CURBRK;
  803.  
  804.         for (;pinvalid == 0 && b < r; p = FROMADJ(TOADJ(r = p)->q_back)) {
  805.                 if ( p == FROMADJ(&adjhead)
  806.                  || (q = (struct overhead *)((char *)p + p->ov_length)) < b
  807.                 ) {
  808.                         pinvalid = 1;
  809.                         q = b;
  810.                 }
  811.  
  812.                 if (q == r)
  813.                         continue;
  814.  
  815.                 ASSERT(q < r,
  816. "\nforget: addresses in adjacency chain are out of order!\n");
  817.  
  818.                 /* end of gap is at break */
  819.                 if (oendfree && r == crbrk) {
  820.                         (void)BRK((char *)q);   /* free it yourself */
  821.                         crbrk = r = q;
  822.                         continue;
  823.                 }
  824.  
  825.                 if (pinvalid)
  826.                         q = (struct overhead *) /* align q pointer */
  827.                                 (((long)q + (NALIGN-1)) & (~(NALIGN-1)));
  828.  
  829.                 l = (char *)r - (char *)q;
  830.                 /*
  831.                  * note: unless something is screwy: (l%NALIGN) == 0
  832.                  * as r should be aligned by this point
  833.                  */
  834.  
  835.                 if (l >= sizeof(struct overhead)) {
  836.                         /* construct busy entry and free it */
  837.                         q->ov_magic = MAGIC_BUSY;
  838.                         q->ov_length = l;
  839.                         insque(TOADJ(q),TOADJ(p));
  840.                         free((char *)q + sizeof(struct overhead));
  841.                 } else if (pinvalid == 0) {
  842.                         /* append it to previous entry */
  843.                         p->ov_length += l;
  844.                         if (p->ov_magic == MAGIC_FREE) {
  845.                                 remque(TOBUK(p));
  846.                                 insque(TOBUK(p),&buckets[mlindx(p->ov_length)]);
  847.                         }
  848.                 }
  849.         }
  850.         endfree = oendfree;
  851.         if (endfree)
  852.                 mlfree_end();
  853.         return;
  854. }
  855. @//E*O*F forget.c//
  856. chmod u=rw,g=r,o=r forget.c
  857.  
  858. echo x - tstmalloc.c
  859. sed 's/^@//' > "tstmalloc.c" <<'@//E*O*F tstmalloc.c//'
  860. /*
  861.  * tstmalloc    this routine tests and exercizes the malloc/free package
  862.  */
  863. #include <stdio.h>
  864. #include <setjmp.h>
  865. #include "malloc.h"
  866.  
  867. jmp_buf env;
  868.  
  869. main(argc,argv)
  870. int argc; char *argv[];
  871. {
  872.         char lin[100], arg1[20], arg2[20], arg3[20];
  873.         char *res, *malloc(), *realloc();
  874.         register struct overhead *p, *q;
  875.         register struct qelem *qp;
  876.         int arg, nargs, argn;
  877.         int l;
  878.         void malerror();
  879.  
  880.         mlabort = &malerror;
  881.         setjmp(env);
  882.  
  883.         for (;;) {
  884.                 printf("*  ");
  885.                 if (fgets(lin,sizeof lin, stdin)== NULL)
  886.                         exit(0);
  887.                 nargs = sscanf(lin,"%s%s%s",arg1,arg2,arg3);
  888.                 switch (arg1[0]) {
  889.  
  890.                 case 'b':
  891.                         if (nargs == 2) {
  892.                                 arg = atoi(arg2);
  893.                                 if (arg<0 ||  arg>=NBUCKETS)
  894.                                         goto bad;
  895.  
  896.                                 qp = &buckets[arg];
  897.                                 printf("Bucket %2d\t\t\t  buk=%08lx %08lx\n",
  898.                                         arg, qp->q_forw,qp->q_back);
  899.                                 qp = qp->q_forw;
  900.                                 for (; qp != &buckets[arg]; qp = qp->q_forw) {
  901.                                         p = FROMBUK(qp);
  902.                                         if (dump(p))
  903.                                                 break;
  904.                                 }
  905.                         } else {
  906.                                 printf("Buckets:");
  907.                                 for (qp=buckets; qp<&buckets[NBUCKETS];qp++){
  908.                                         if (qp->q_forw != qp)
  909.                                                 printf(" %d", qp-buckets);
  910.                                 }
  911.                                 printf("\n");
  912.                         }
  913.                         break;
  914.                 case 'e':
  915.                         endfree = 1;
  916.                         break;
  917.                 case 'E':
  918.                         endfree = 0;
  919.                         break;
  920.                 case 'f':
  921.                         if (nargs != 2) goto bad;
  922.                         sscanf(arg2,"%lx",&arg);
  923.                         printf("free(%x)\n",arg);
  924.                         free(arg);
  925.                         break;
  926.                 case 'F':
  927.                         if (nargs != 2) goto bad;
  928.                         sscanf(arg2,"%lx",&arg);
  929.                         printf("forget(%x)\n",arg);
  930.                         forget(arg);
  931.                         break;
  932.                 case 'h':
  933.                         printf("\
  934. b       print bucket chains that aren't empty\n\
  935. b [n]   trace through bucket chains\n\
  936. e       turn on freeing of end of memory\n\
  937. E       turn off freeing of end of memory\n\
  938. f addr          free addr\n\
  939. F addr          forget below addr\n\
  940. h       print this help file\n\
  941. m bytes         malloc bytes\n\
  942. q       quit\n\
  943. r addr bytes    realloc\n\
  944. s       print break addr\n\
  945. S       sbrk count\n\
  946. t       trace through adjacency chain\n\
  947. ");
  948.                         break;
  949.                 case 'm':
  950.                         if (nargs != 2) goto bad;
  951.                         arg = atoi(arg2);
  952.                         res = malloc(arg);
  953.                         printf("malloc(%d) = %lx\n",arg, res);
  954.                         break;
  955.                 case 'r':
  956.                         if (nargs != 3) goto bad;
  957.                         sscanf(arg2,"%lx",&arg);
  958.                         argn = atoi(arg3);
  959.                         res = realloc(arg,argn);
  960.                         printf("realloc(%lx,%d) = %lx\n",arg,argn,res);
  961.                         break;
  962.                 case 'q':
  963.                         exit(0);
  964.                         break;
  965.                 case 's':
  966.                         printf("brk = %08x\n",sbrk(0));
  967.                         break;
  968.                 case 'S':
  969.                         if (nargs != 2) goto bad;
  970.                         sscanf(arg2,"%ld",&arg);
  971.                         printf("sbrk(%d)\n",arg);
  972.                         sbrk(arg);
  973.                         break;
  974.                 case 't':
  975.                         printf("\t\t\t\t\t\thead    adj=%08lx %08lx\n",
  976.                                 adjhead.q_forw,adjhead.q_back);
  977.                         for (qp = adjhead.q_forw; qp!=&adjhead; qp=qp->q_forw) { 
  978.                                 p = FROMADJ(qp);
  979.                                 if (dump(p))
  980.                                         break;
  981.                                 q = FROMADJ(qp->q_forw);
  982.                                 if (q==FROMADJ(&adjhead))
  983.                                         q = (struct overhead *)sbrk(0);
  984.                                 l = (char *)q - (char *)p - p->ov_length;
  985.                                 if (l>0)
  986.                                         printf("%08x free space  len=%8d\n",
  987.                                                 (char *)p + p->ov_length, l);
  988.                         }
  989.                         break;
  990.                 default:
  991.         bad:            printf("Bad command\n");
  992.                 }
  993.         }
  994. }
  995.  
  996. dump(p)
  997. register struct overhead *p;
  998. {
  999.         register char *s;
  1000.         int stat = 0;
  1001.  
  1002.         if (p->ov_magic == MAGIC_FREE)
  1003.                 s = "MAGIC_FREE ";
  1004.         else if (p->ov_magic == MAGIC_BUSY) 
  1005.                 s = "MAGIC_BUSY ";
  1006.         else {
  1007.                 s = "BAD MAGIC  ";
  1008.                 stat = 1;
  1009.         }
  1010.                 
  1011.         printf( "%08x %s len=%8d buk=%08x %08x adj=%08x %08x\n",
  1012.                 (&p[1]),s,p->ov_length,p->ov_buk.q_forw,p->ov_buk.q_back,
  1013.                 p->ov_adj.q_forw,p->ov_adj.q_back
  1014.         );
  1015.         return(stat);
  1016. }
  1017.  
  1018. void
  1019. malerror()
  1020. {
  1021.         write(2,"malloc error\n",13);
  1022.         longjmp(env,1);
  1023. }
  1024. @//E*O*F tstmalloc.c//
  1025. chmod u=rw,g=r,o=r tstmalloc.c
  1026.  
  1027. echo x - asm.sed
  1028. sed 's/^@//' > "asm.sed" <<'@//E*O*F asm.sed//'
  1029. s/calls $2,_insque/insque       *(sp)+,*(sp)+/
  1030. s/calls $1,_remque/remque       *(sp)+,r0/
  1031. @//E*O*F asm.sed//
  1032. chmod u=rw,g=r,o=r asm.sed
  1033.  
  1034. echo x - malloc.adb
  1035. sed 's/^@//' > "malloc.adb" <<'@//E*O*F malloc.adb//'
  1036. @.>7
  1037. @./"adj "XX"buk "XX"MAG "X"len "Dn
  1038. (*(<7))
  1039. @//E*O*F malloc.adb//
  1040. chmod u=rw,g=r,o=r malloc.adb
  1041.  
  1042. exit 0
  1043. --------Cut Here----------
  1044.  
  1045.  
  1046. From mnetor!seismo!caip!pyrnj!mirror!sources-request Fri Jul 18 22:29:06 EDT 1986
  1047. Article 447 of mod.sources:
  1048. Relay-Version: version B 2.10.2 9/18/84; site lsuc.UUCP
  1049. Path: lsuc!mnetor!seismo!caip!pyrnj!mirror!sources-request
  1050. >From: sources-request@mirror.UUCP
  1051. Newsgroups: mod.sources
  1052. Subject: v06i057:  Missing makefile for "malloc" posting (malloc.mk)
  1053. Message-ID: <144@mirror.UUCP>
  1054. Date: 16 Jul 86 12:47:13 GMT
  1055. Date-Received: 17 Jul 86 02:56:50 GMT
  1056. Sender: rs@mirror.UUCP
  1057. Lines: 50
  1058. Approved: rs@mirror.UUCP
  1059.  
  1060. Submitted by: cca!astrovax!wls (William L. Sebok)
  1061. Mod.sources: Volume 6, Issue 57
  1062. Archive-name: malloc.mk
  1063.  
  1064. Unfortunately in my last posting ('A "smarter" malloc') I forgot to include
  1065. the Makefile.  I have been cut off from the news for about a week as astrovax
  1066. undergoes transformation from a Vax 750 running 4.2 BSD to a Vax 8200 running
  1067. Ultrix v1.2.  Because of this I didn't realize it was missing till I started
  1068. getting letters about a missing Makefile.  Here it is the Makefile for a Vax.
  1069. Changes for other machines should be obvious.
  1070.  
  1071. Bill Sebok                      Princeton University, Astrophysics
  1072. {allegra,akgua,cbosgd,decvax,ihnp4,noao,philabs,princeton,vax135}!astrovax!wls
  1073.  
  1074. [  The fault is really mine; I'm supposed to catch things like that...  -r$ ]
  1075. -----Cut here----
  1076. cat >Makefile <<'!E!O!T!'
  1077. LARGS=
  1078. CARGS= -O -Ddebug
  1079. CURBRK=
  1080.  
  1081. all:    malloc.o free.o realloc.o forget.o
  1082.         
  1083. # for vax users
  1084. .c.o:   malloc.h $*.c
  1085.         ${CC} -S ${CARGS} ${CURBRK} $*.c
  1086.         sed -f asm.sed $*.s | as -o $*.o
  1087.         ld -x -r $*.o
  1088.         mv a.out $*.o
  1089.  
  1090. # for non-vax-users
  1091. #.c.o:  malloc.h $*.c
  1092. #       ${CC} -c ${CARGS} ${CURBRK} $*.c
  1093.         
  1094.  
  1095. tstmalloc:      tstmalloc.o malloc.o free.o realloc.o forget.o
  1096.         ${CC} ${LARGS} -o tstmalloc tstmalloc.o malloc.o free.o realloc.o \
  1097.                 forget.o
  1098.  
  1099. vgrind:
  1100.         vgrind malloc.h malloc.c free.c realloc.c forget.c
  1101.  
  1102. shar:
  1103.         shar > shar.out README Makefile malloc.3 forget.3 malloc.h malloc.c \
  1104.         free.c realloc.c forget.c tstmalloc.c asm.sed malloc.adb
  1105.  
  1106. clean:
  1107.         rm -f tstmalloc *.[os] shar.out OUT core
  1108. !E!O!T!
  1109. exit 0
  1110.  
  1111.  
  1112.   $